class          = {}
class.error    = {}
class.instance = {}

class.error.readOnly = function()
    error("Instance members are read only, use O.O. bingo")
end

class.check = function(c)
    if type(c) == "table" and getmetatable(c).__isclass ~= nil then
        return true
    else
        error("Attempt to resolve class failed!")
    end
end

-- get a member of the object specified
class.getMember = function(c, member)
    if class.check(c) then
        local members    = getmetatable(c).__members
        local cppmethods = getmetatable(c).__cppmethods
        if members[member] ~= nil then
            return members[member]
        elseif cppmethods[member] ~= nil then
            return cppmethods[member]
        end
        error("Attempt to resolve member '"..member.."' failed!")
    end
end

class.setMember = function(c, member, value)
    if class.check(c) then
        getmetatable(c).__members[member] = value
    end
end

class.instance.check = function(c)
    if type(c) == "table" and getmetatable(c).__class ~= nil then
        return true
    else
        error("Attempt to resolve instance failed!")
    end
end

class.instance.getMember = function(this, method)
    if class.instance.check(this) then
        return class.getMember(getmetatable(this).__class, method)
    end
end

class.instance.cppconstruct = function(this, cppcallbackindex, ...)
    getmetatable(this).__cppobject = SG2.callback_function(cppcallbackindex, ...)
    return this
end

class.instance.cppcall = function(this, cppcallbackindex, ...)
    if getmetatable(this).__cppobject ~= nil then
        return SG2.callback_function(cppcallbackindex, getmetatable(this).__cppobject, ...)
    else
        error("Attempt to resolve c++ instance failed!")
    end
end

class.bindMember = function(c, member, cppcallbackindex)
    if class.check(c) then
        if member == "__construct" then
            getmetatable(c).__cppmethods[member] = function(this,...)
                return class.instance.cppconstruct(this,cppcallbackindex,...)
            end
        else
            getmetatable(c).__cppmethods[member] = function(this,...)
                return class.instance.cppcall(this,cppcallbackindex,...)
            end
        end
    end
end

-- constructor
class.construct = function(c, ...)
    if class.check(c) then
        local new_instance  = {}
        local new_metatable = {}

        new_metatable.__class    = c
        new_metatable.__index    = class.instance.getMember
        new_metatable.__newindex = class.error.readOnly

        setmetatable(new_instance, new_metatable)

        class.getMember(c, "__construct")(new_instance, ...)

        return new_instance
    end
end

-- create a new class type
class.new = function( ... )
    local new_class     = {}
    local new_metatable = {}

    new_class.bindMember              = class.bindMember
    new_class.getMember               = class.getMember
    new_class.setMember               = class.setMember

    new_metatable.__isclass           = true
    new_metatable.__members           = {}
    new_metatable.__cppmethods        = {}

    new_metatable.__call              = class.construct
    new_metatable.__index             = class.getMember
    new_metatable.__newindex          = class.setMember

    -- assign the meta table
    setmetatable(new_class, new_metatable)

    return new_class
end
